#include "StdAfx.h"
#include "MainView.h"
#include "RibbonResultView.h"
#include "RibbonRes.h"
#include "RibbonCompiler.h"
#include "Resource.h"
#include "ShellAPI.h"
#include "RibbonInfo.h"
#include "Util.h"
#include <memory>
#include "commctrl.h"

using namespace std;
using namespace std::tr1;


wchar_t g_sUICCPath[MAX_PATH] = L"C:\\Program Files\\Microsoft SDKs\\Windows\\v7.0\\Bin\\UICC.exe";
wchar_t g_sRCPath[MAX_PATH] = L"C:\\Program Files\\Microsoft SDKs\\Windows\\v7.0\\Bin\\RC.exe";
#ifdef _AMD64_
wchar_t g_sLINKPath[MAX_PATH] = L"C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\bin\\amd64\\link.exe";
#else
wchar_t g_sLINKPath[MAX_PATH] = L"C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\bin\\link.exe";
#endif


HWND CMainView::s_hMainViewWnd = 0; 
HINSTANCE CMainView::s_hInstance = 0;

void CMainView::AddPathCommon7IDEDir()
{
	wchar_t path[2048];
	
	wstring sLinkPath(g_sLINKPath);
	wstring linkDir = sLinkPath.substr(0, sLinkPath.find_last_of(L"\\"));
	wstring ideDir = linkDir + L"\\..\\..\\Common7\\IDE";
	GetEnvironmentVariable(L"PATH", (LPWSTR)&path, 2048);
	wstring newPath(path);
	
	newPath = ideDir + L";" + newPath;
	SetEnvironmentVariable(L"PATH", newPath.c_str());
}


HRESULT CMainView::LoadSettings()
{
	HKEY hKeySoftware;
	if (::RegOpenKey(HKEY_CURRENT_USER, L"SOFTWARE\\RibbonExplorer", &hKeySoftware) != ERROR_SUCCESS)
		return E_FAIL;

	wchar_t sBuffer[MAX_PATH];
	
	DWORD dwBufferSize;
	dwBufferSize = MAX_PATH * sizeof(wchar_t);
	DWORD type;
	if (::RegQueryValueEx(hKeySoftware, L"UICCPath", NULL, &type, (LPBYTE)sBuffer, &dwBufferSize) == ERROR_SUCCESS
		&& type == REG_SZ)
		wcscpy_s(g_sUICCPath, MAX_PATH, sBuffer);

	dwBufferSize = MAX_PATH * sizeof(wchar_t);
	if (::RegQueryValueEx(hKeySoftware, L"RCPath", NULL, &type, (LPBYTE)sBuffer, &dwBufferSize) == ERROR_SUCCESS
		&& type == REG_SZ)
		wcscpy_s(g_sRCPath, MAX_PATH, sBuffer);

	dwBufferSize = MAX_PATH * sizeof(wchar_t);
	if (::RegQueryValueEx(hKeySoftware, L"LINKPath", NULL, &type, (LPBYTE)sBuffer, &dwBufferSize) == ERROR_SUCCESS
		&& type == REG_SZ)
		wcscpy_s(g_sLINKPath, MAX_PATH, sBuffer);

	::RegCloseKey(hKeySoftware);

	AddPathCommon7IDEDir();

	return S_OK;
}

HRESULT CMainView::SaveSettings()
{
	HKEY hKeySoftware;
	if (::RegOpenKey(HKEY_CURRENT_USER, L"SOFTWARE\\RibbonExplorer", &hKeySoftware) != ERROR_SUCCESS)
	{
		if (::RegCreateKey(HKEY_CURRENT_USER, L"SOFTWARE\\RibbonExplorer", &hKeySoftware) != ERROR_SUCCESS)
			return E_FAIL;
	}

	DWORD dwBufferSize;
	dwBufferSize = MAX_PATH * sizeof(wchar_t);
	::RegSetValueEx(hKeySoftware, L"UICCPath", NULL, REG_SZ, (BYTE*)g_sUICCPath, (DWORD)(wcslen(g_sUICCPath) + 1) * sizeof(wchar_t));
		
	dwBufferSize = MAX_PATH * sizeof(wchar_t);
	::RegSetValueEx(hKeySoftware, L"RCPath", NULL, REG_SZ, (BYTE*)g_sRCPath, (DWORD)(wcslen(g_sRCPath) + 1) * sizeof(wchar_t));

	dwBufferSize = MAX_PATH * sizeof(wchar_t);
	::RegSetValueEx(hKeySoftware, L"LINKPath", NULL, REG_SZ, (BYTE*)g_sLINKPath, (DWORD)(wcslen(g_sLINKPath) + 1) * sizeof(wchar_t));

	::RegCloseKey(hKeySoftware);

	return S_OK;
}

RECT CMainView::GetTabContainerRectangle() const
{
	RECT r;
	GetClientRect(s_hMainViewWnd, &r);
	UINT32 height;
	const_cast<CMainView *>(this)->GetRibbonHeight(&height);
	r.top = height;

	return r;
}

void CMainView::UpdateWindowSise(RECT rect)
{
	m_tabContainer->UpdateTabSize(GetTabContainerRectangle());
}

HRESULT CMainView::OnAfterCreateRibbon(HWND hWnd, HINSTANCE hInstance)
{
	LoadSettings();

	s_hMainViewWnd = hWnd;
	s_hInstance = hInstance;

	RECT r = GetTabContainerRectangle();
	m_tabContainer = shared_ptr<CTabContainer>(new CTabContainer(hWnd, hInstance, r));
	CreateRibbonXMLSourceTab();
	return S_OK;
}


void CMainView::CreateRibbonXMLSourceTab()
{
	m_ribbonXMLSourceTabView = shared_ptr<CRibbonXMLSourceTabView>(new CRibbonXMLSourceTabView());
	m_tabContainer->AddTab(m_ribbonXMLSourceTabView);
	
	

	int argc = 0;
	wchar_t **argv = ::CommandLineToArgvW(::GetCommandLine(), &argc);

	if (argc < 2) //nothing to load
	{
		m_xmlFilePath = wstring(L"");
		return;
	}
	
	LoadRibbonFromFile(argv[1]);

	
}

void CMainView::SetWindowTitle(const wstring &info)
{
	wstring title(L"RibbonExplorer - ");
	title += info;
	SetWindowText(s_hMainViewWnd, title.c_str());
}

void CMainView::LoadRibbonFromFile(const wstring& szFileName)
{
	m_xmlFilePath = szFileName;
	const wstring &xmlText = CUtil::ReadFileText(m_xmlFilePath);
	m_ribbonXMLSourceTabView->GetRichEdit()->Clear();
	m_ribbonXMLSourceTabView->GetRichEdit()->AppendText(xmlText);
	SetWindowTitle(szFileName);
}



void CMainView::SaveRibbonToFile(const wstring& szFileName)
{
	m_xmlFilePath = szFileName;	//'Save as' replaces the current file name
	wstring ribbonText = m_ribbonXMLSourceTabView->GetRichEdit()->GetText();
	CUtil::WriteFileText(m_xmlFilePath, ribbonText);
}

HRESULT CMainView::ShowRibbon()
{
	//TODO: save the file if it has changed
	if (m_xmlFilePath == wstring(L""))
	{
		m_xmlFilePath = CUtil::GetTempFilePath(L"xml");
		CUtil::WriteFileText(m_xmlFilePath, m_ribbonXMLSourceTabView->GetRichEdit()->GetText());
	}

	CRibbonCompiler ribbonCompiler(m_xmlFilePath, g_sUICCPath, g_sRCPath, g_sLINKPath);
	wstring szResourceDllName = CUtil::GetTempFilePath(L"dll");
	DWORD result = ribbonCompiler.Compile(szResourceDllName);
	
	if (result == 0)
	{
		shared_ptr<CRibbonInfo> ribbonInfo(new CRibbonInfo(ribbonCompiler));

		if (m_hRibbonResultManagerViewWnd)
		{
			DestroyWindow(m_hRibbonResultManagerViewWnd);
		}
		CreateResultManager(ribbonInfo, szResourceDllName,  L"APPLICATION_RIBBON");
	}
	
	ClearOrCreateTabView<CCompilerOutputTabView>(m_ribbonCompilersTabView);
	ClearOrCreateTabView<CRibbonResourceFileTabView>(m_ribbonResourceFileTabView);
	ClearOrCreateTabView<CRibbonHeaderFileTabView>(m_ribbonHeaderFileTabView);


	m_ribbonCompilersTabView->GetRichEdit()->AppendText(ribbonCompiler.GetOutput());
	m_ribbonCompilersTabView->MarkLineContainigStringInColor(L"warning", RGB(200,0,200));
	m_ribbonCompilersTabView->MarkLineContainigStringInColor(L"error", RGB(200,0,0));

	m_ribbonResourceFileTabView->GetRichEdit()->AppendText(ribbonCompiler.GetResourceFileText());

	m_ribbonHeaderFileTabView->GetRichEdit()->AppendText(ribbonCompiler.GetHeaderFileText());

	return S_OK;
}


INT_PTR CALLBACK ToolPathsDialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;

	switch (message)
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		case IDOK:
			{
				::GetDlgItemText(hWnd, IDC_EDIT_UICC, g_sUICCPath, MAX_PATH);
				::GetDlgItemText(hWnd, IDC_EDIT_RC, g_sRCPath, MAX_PATH);
				::GetDlgItemText(hWnd, IDC_EDIT_LINK, g_sLINKPath, MAX_PATH);
				CMainView::SaveSettings();
				EndDialog(hWnd, NULL);
			}
			break;
		case IDCANCEL:
			EndDialog(hWnd, NULL);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_INITDIALOG:
		DefWindowProc(hWnd, message, wParam, lParam);
		CMainView::LoadSettings();
		::SetDlgItemText(hWnd, IDC_EDIT_UICC, g_sUICCPath);
		::SetDlgItemText(hWnd, IDC_EDIT_RC, g_sRCPath);
		::SetDlgItemText(hWnd, IDC_EDIT_LINK, g_sLINKPath);
		break;
	case WM_DESTROY:
		EndDialog(hWnd, NULL);
		DestroyWindow(hWnd);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}


HRESULT CMainView::ToolPaths()
{
	::DialogBoxW(s_hInstance, MAKEINTRESOURCE(IDD_DIALOG_TOOLPATHS), s_hMainViewWnd, ToolPathsDialogProc);
	return S_OK;
}


// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;

			// g_hLink is the handle of the SysLink control.
	case WM_NOTIFY:
		switch (((LPNMHDR)lParam)->code)
		{
			case NM_CLICK:
			case NM_RETURN:
				{
					PNMLINK pNMLink = (PNMLINK)lParam;
					LITEM item = pNMLink->item;
					ShellExecute(NULL, L"open", item.szUrl, NULL, NULL, SW_SHOW);
				}
		}
		break;

	case WM_CLOSE:
		EndDialog(hDlg, IDOK);
		return (INT_PTR)TRUE;
	}
	return DefWindowProc(hDlg, message, wParam, lParam);
}



HRESULT CMainView::ShowAboutDialog() const
{
	::DialogBoxW(s_hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), s_hMainViewWnd, About);
	return S_OK;
}

HRESULT CMainView::Save()
{
	if (m_xmlFilePath.empty())
		return SaveAs();
	SaveRibbonToFile(m_xmlFilePath);
	return S_OK;
}

HRESULT CMainView::SaveAs()
{
	const wstring& saveTo = CUtil::GetOpenFileName(L"Choose save location...", s_hMainViewWnd, /*mustExist*/false);
	SaveRibbonToFile(saveTo);
	SetWindowTitle(saveTo);
	return S_OK;
}

HRESULT CMainView::Load()
{
	const wstring& loadFrom = CUtil::GetOpenFileName(L"Choose a ribbon markup file...", s_hMainViewWnd);
	LoadRibbonFromFile(loadFrom);
	return S_OK;
}

HRESULT CMainView::Exit()
{
	PostQuitMessage(0);
	return S_OK;
}

HRESULT CMainView::Copy()
{
	m_tabContainer->Copy();

	return S_OK;
}

HRESULT CMainView::Execute(UINT nCmdID,
		UI_EXECUTIONVERB verb, 
		__in_opt const PROPERTYKEY* key,
		__in_opt const PROPVARIANT* ppropvarValue,
		__in_opt IUISimplePropertySet* pCommandExecutionProperties)
{
	HRESULT hr = S_OK;

	switch (verb)    
	{  
	case UI_EXECUTIONVERB_EXECUTE:
		if (nCmdID == cmdSave)
		{
			return Save();
		}
		if (nCmdID == cmdSaveAs)
		{
			return SaveAs();
		}
		if (nCmdID == cmdLoad)
		{
			return Load();
		}
		if (nCmdID == cmdShowRibbon)
		{
			return ShowRibbon();
		}
		if (nCmdID == cmdToolPaths)
		{
			return ToolPaths();
		}
		if (nCmdID == cmdAbout)
		{
			return ShowAboutDialog();
		}
		if (nCmdID == cmdExit)
		{
			return Exit();
		}
		if(nCmdID == cmdCopy)
		{
			return Copy();
		}
		break;
	}	    
	return hr;
}

HRESULT CMainView::OnCreateUICommand(UINT32 nCmdID, __in UI_COMMANDTYPE typeID, __deref_out IUICommandHandler** ppCommandHandler) 
{
	return QueryInterface(IID_PPV_ARGS(ppCommandHandler));
}

void CMainView::CreateResultManager(const shared_ptr<CRibbonInfo> &ribbonInfo, const wstring &szResourceDllName, PCWSTR szRibbonResourceName)
{
	CRibbonResultManagerView::RegisterClass(s_hInstance);
	m_hRibbonResultManagerViewWnd = CreateWindowEx(0, RIBBONRESULTMANAGERVIEW_WNDCLASS, L"Ribbon Result Manager", WS_OVERLAPPEDWINDOW,
	  CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, s_hInstance, NULL);
		
	m_pRibbonResultManagerView = NULL;
	CComObject<CRibbonResultManagerView>::CreateInstance(&m_pRibbonResultManagerView);
	m_pRibbonResultManagerView->SetParameters(ribbonInfo, szResourceDllName, szRibbonResourceName);	
	wstring ribbonResourceDllPath = m_pRibbonResultManagerView->GenerateResultManagerRibbon();
	HRESULT hResult = CRibbonResultManagerView::CreateFromResourceDLL(m_pRibbonResultManagerView, m_hRibbonResultManagerViewWnd, s_hInstance, ribbonResourceDllPath.c_str(), L"APPLICATION_RIBBON");
	if (!SUCCEEDED(hResult))
		throw L"Can't create Ribbon Manager view";
}
